package com.miplus.ccrm.core.service.strategy;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.CmdResVo;
import com.miplus.ccrm.common.EnumRCode;
import com.miplus.ccrm.common.JPubUtils;
import com.miplus.ccrm.common.ServiceException;
import com.miplus.ccrm.core.controller.vo.credit.DistCreditcaseVo;
import com.miplus.ccrm.core.controller.vo.credit.DistObjectVo;
import com.miplus.ccrm.core.controller.vo.credit.DistResVo;
import com.miplus.ccrm.core.controller.vo.credit.ValRadioVo;
import com.miplus.ccrm.core.controller.vo.strategy.*;
import com.miplus.ccrm.core.pojo.*;
import com.miplus.ccrm.core.mapper.CfgAssignsetMapper;
import com.miplus.ccrm.core.pojo.model.AutoAssign;
import com.miplus.ccrm.core.service.crd.FiCreditcasesHistService;
import com.miplus.ccrm.core.service.crd.FiCreditcasesService;
import com.miplus.ccrm.core.utils.EnumFiCaseQueue;
import com.miplus.ccrm.core.utils.EnumFiCaseStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.locks.Condition;

/**
* @author pc
* @description 针对表【cfg_assignset】的数据库操作Service实现
* @createDate 2024-04-16 15:12:00
*/
@Service
@Slf4j
public class CfgAssignsetServiceImpl extends MPJBaseServiceImpl<CfgAssignsetMapper, CfgAssignset>
    implements CfgAssignsetService{

    @Resource
    private CfgAssignratioService cfgAssignratioService;

    @Resource
    private FiCreditcasesService fiCreditcasesService;

    @Resource
    private FiCreditcasesHistService fiCreditcasesHistService;


    @Override
    public IPage<AssSetResVo> assignSetList(String $usrid, AssSetReqVo paras)
    {
        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                AssSetResVo.class,
                new MPJLambdaWrapper<CfgAssignset>()
                        .selectAs("(select g.grpname from sys_grp g where g.grpid=t.grpid)", AssSetResVo::getGrpname)
                        .selectAs("fun_getnames('ACTIVITY.QUERY.DISMODE',t.mode)",AssSetResVo::getModedsc)
                        .selectAs("fun_getnames('PUBLIC.ENSTATUS',t.status)",AssSetResVo::getStatusdsc)
                        .selectAll(CfgAssignset.class)
                        .eq(JPubUtils.IsNotEmpty(paras.getGrpid()),CfgAssignset::getGrpid,paras.getGrpid())
                        .eq(JPubUtils.IsNotEmpty(paras.getStatus()),CfgAssignset::getStatus,paras.getStatus())
                        .orderByAsc(CfgAssignset::getGrpid)
        );
    }

    @Override
    public CmdResVo assignSetUpdate(String $usrid, AssSetEditVo paras)
    {
        CfgAssignset def=new CfgAssignset();
        BeanUtils.copyProperties(paras,def);
        def.setMddt(new Date());
        def.setMdusr($usrid);
//        int ret=baseMapper.update(def,
//                new MPJLambdaWrapper<CfgAssignset>().eq(CfgAssignset::getGrpid,paras.getGrpid())
//        );
        updateById(def);
        cfgAssignratioService.getBaseMapper().delete(
                new QueryWrapper<CfgAssignratio>().eq("assign_id",paras.getAssignId())
        );
        AddAssignUsr(paras,paras.getAssignId());
        return new CmdResVo(1,def.getAssignId().toString());
    }

    @Override
    public CmdResVo assignSetInsert(String $usrid,AssSetEditVo paras)
    {
        //CfgAssignset def=baseMapper.selectById(paras.getGrpid());
        CfgAssignset def=baseMapper.selectById(paras.getAssignId());
        if(def!=null){
            throw new ServiceException(EnumRCode.HasExist.value, EnumRCode.HasExist.name);
        }
        def=new CfgAssignset();
        BeanUtils.copyProperties(paras,def);
        def.setStartrun(1);
        def.setMddt(new Date());
        def.setMdusr($usrid);
        save(def);
        //paras.setAssignId(def.getAssignId());
        AddAssignUsr(paras,def.getAssignId());
        return new CmdResVo(1,def.getAssignId().toString());
    }

    private void AddAssignUsr(AssSetEditVo paras,Long assignId)
    {
        if(JPubUtils.IsEmpty(paras.getAssUsrList()))
            return;
        cfgAssignratioService.remove(
                new LambdaQueryWrapper<CfgAssignratio>().eq(CfgAssignratio::getAssignId,assignId));
        for(AssRatioAddVo addVo : paras.getAssUsrList()){
            CfgAssignratio cfgAssignratio=new CfgAssignratio();
            cfgAssignratio.setGrpid(paras.getGrpid());
            cfgAssignratio.setUsrid(addVo.getUsrid());
            cfgAssignratio.setRatio(addVo.getRatio());
            cfgAssignratio.setAssignId(assignId);
            cfgAssignratioService.save(cfgAssignratio);
        }
    }
//    @Override
//    public CmdResVo assignSetDelete(String grpid)
//    {
//        int ret=baseMapper.delete(new QueryWrapper<CfgAssignset>()
//                        .eq("grpid", grpid)
//        );
//        cfgAssignratioService.getBaseMapper().delete(
//                new QueryWrapper<CfgAssignratio>().eq("grpid",grpid)
//        );
//        return new CmdResVo(ret,grpid);
//    }
    @Override
    public CmdResVo assignSetDelete(Long assignId)
    {
//        int ret=baseMapper.delete(new QueryWrapper<CfgAssignset>()
//                .eq("grpid", grpid)
//        );
        removeById(assignId);
        cfgAssignratioService.getBaseMapper().delete(
                new QueryWrapper<CfgAssignratio>().eq("assign_id",assignId)
        );
        return new CmdResVo(1,assignId.toString());
    }
    @Override
    public List<AssRatioResVo> assignRatioList(String grpid, Long assignId)
    {
        return baseMapper.assignRatioList(grpid, assignId);
    }

    public List<AssRatioResVo> assignRatioList2(AssRatioReqVo assRatioReqVo)
    {
        return baseMapper.assignRatioListByUsers(assRatioReqVo.getGrpid(), assRatioReqVo.getAssignId(),assRatioReqVo.getUsers());
    }
//    @Override
//    public List<AssRatioResVo> assignRatioList(Long assignId)
//    {
//        return baseMapper.assignRatioList(assignId);
//    }
    @Override
    public CmdResVo autoAssign(CfgRuleTaskSteps cfgRuleTaskSteps, CfgAssignset cfgAssignset,String sql) {
////        List<CfgAssignset> list = list(new QueryWrapper<CfgAssignset>()
////                .eq("status", 1)
////                .eq("startrun", 1));
//
//        XxlJobHelper.log("XXXL-JOB-autoAssign 派工模版:" + list.size() + "条");
//        String sql = cfgRuleTaskSteps.getFilterSql();
//        String sql = cfgRuleTaskStepsService.getExcludeBlackSql(cfgRuleTaskSteps);
//        if(StringUtils.isEmpty(sql))
//            sql = " 1=1 ";
//        //客户黑名单。
//        if( cfgRuleTaskSteps.getExcludeBlack() == 1)
//            sql += " and not exists (select 1 from con_blacklist cbl where cbl.customernumber = cu.customernumber and cbl.type = 1 )";
//
//        if( cfgRuleTaskSteps.getExcludeWhite() == 1)
//            sql += " and not exists ( select 1 from con_blacklist cbl where cbl.customernumber = cu.customernumber and cbl.type = 2 )";
//
//        if( cfgRuleTaskSteps.getExcludeStop() == 1)
//            //sql += " and fi_hasstopcall(fc.creditcaseid,'CASE')=0 ";
//            sql += "  and  not exists( SELECT 1  \n" +
//                    "    FROM fi_stopcall s  \n" +
//                    "    WHERE s.stopkey = fc.creditcaseid and s.stoptype = 'CASE' AND s.status = 2 )";
//        if(cfgRuleTaskSteps.getExcludeCustomerStop() == 1)
//            //sql += " and fi_hasstopcall(cu.customernumber,'CUSTOMER')=0 ";
//            sql += "  and  not exists( SELECT 1  \n" +
//                    "    FROM fi_stopcall s  \n" +
//                    "    WHERE s.stopkey = cu.customernumber and s.stoptype = 'CUSTOMER' AND s.status = 2 )";

        List<FiCreditcases> caselist = fiCreditcasesService.getAssignCollectlist(sql,cfgAssignset.getGrpid());

        //XxlJobHelper.log("XXL-JOB-autoAssign 符合条件的案件:" + caselist.size() + "条.");
        return assign(caselist,cfgRuleTaskSteps.getRuleStepId(), cfgAssignset,1,"system");
    }

    /**
     *
     * @param caselist:查询结果队列
     * @param cfgAssignset：坐席配置。
     * @param assignType：1：自动分配，2：人工派工
     */
    private CmdResVo assign(List<FiCreditcases> caselist, Long ruleStepId, CfgAssignset cfgAssignset, Integer  assignType, String usrId )
    {

        try {
            int totalCnt = caselist.size();
            int sumamount = caselist.stream().map(FiCreditcases::getCpTotalamt).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).intValue();
            if (totalCnt == 0)
                return new CmdResVo(-1,"没有找到待派工的案件");

            List<CfgAssignratio> users = cfgAssignratioService.list(new QueryWrapper<CfgAssignratio>()
                    .eq("assign_id", cfgAssignset.getAssignId())
            );
            //  XxlJobHelper.log("XXL-JOB-autoAssign 被分配坐席:" + users.size() + "条.");
            if(users == null || users.size() == 0 )
                return new CmdResVo(-1,"没有指定相应的催员");

            int startpos = 0;
            boolean firstSort = true;
            int mode = cfgAssignset.getMode();
            //如果催员数量为1，激动改成平均模式。
            if(users.size() == 1)
                mode = 1;

            List<AutoAssign> usrlist = new ArrayList<>();
            AutoAssign model = null;
            int needCnt = 0;

            for (int i = 0; i < (long) users.size(); i++) {
                model = new AutoAssign();
                model.setSysUsr(users.get(i));
                model.setNum(0);
                model.setAmount(BigDecimal.valueOf(0));
                model.setAssignRatio(0.0);
                if( mode == 1){
                    model.setRatio(100.0/users.size());
                    model.setTagetNum( totalCnt/users.size() + (totalCnt % users.size() > i ? 1:0));
                }
                else {
                    model.setRatio(users.get(i).getRatio());
                    model.setTagetNum(1.0 * totalCnt * model.getRatio() / 100);
                }
                model.setTagetAmt(1.0 * sumamount * model.getRatio()/100);
                model.setAssignCaseList( new ArrayList<>());
                model.setOverRatio(0.0);
                usrlist.add(model);
            }
            InitAssignList(mode, usrlist, caselist);


            //usrlist.sort(Comparator.comparing(AutoAssign::getRatio).reversed());
            for(int loop =0; loop<3; loop++){
                needCnt = 0;
                for( int i=0; i< usrlist.size(); i++)
                    needCnt += usrlist.get(i).getTargetDistNum()[loop];
                if( needCnt == 0)
                    continue;
                List<FiCreditcases> assignCaseVos = getDistObject(startpos, needCnt, caselist);
                Collections.shuffle(assignCaseVos);
                for (int grpIndex = 0; grpIndex < usrlist.size(); grpIndex++) {
                    usrlist.get(grpIndex).setDistNum(0);
                }
                for (FiCreditcases x : assignCaseVos) {
                    for (int grpIndex = 0; grpIndex < usrlist.size(); grpIndex++) {
                        if(  usrlist.get(grpIndex).getDistNum() >=  usrlist.get(grpIndex).getTargetDistNum()[loop])
                            continue;
                        usrlist.get(grpIndex).setDistNum(usrlist.get(grpIndex).getDistNum()+1);
                        usrlist.get(grpIndex).setNum(usrlist.get(grpIndex).getNum() + 1);
                        usrlist.get(grpIndex).setAmount(usrlist.get(grpIndex).getAmount().add(x.getCpTotalamt()));
                        x.setSendtousr(usrlist.get(grpIndex).getSysUsr().getUsrid());
                        usrlist.get(grpIndex).getAssignCaseList().add(x);
                        break;
                    }
                }
                startpos += needCnt;
                assignCaseVos.clear();
            }
            usrlist.forEach(x->{
                x.setOverRatio(x.getAmount().doubleValue()/x.getTagetAmt());
            });

            while(true) {
                usrlist.sort(Comparator.comparing(AutoAssign::getOverRatio).reversed());
                if (usrlist.get(0).getOverRatio() > 1.05 || usrlist.get(usrlist.size()-1).getOverRatio()< 0.95)
                {
                    //调整 调转方案，最大比例和最小比例间调转。
                    usrlist.get(0).getAssignCaseList().sort(Comparator.comparing(FiCreditcases::getCpTotalamt).reversed());
                    usrlist.get(usrlist.size()-1).getAssignCaseList().sort(Comparator.comparing(FiCreditcases::getCpTotalamt).reversed());
                    int ret = swapCase(usrlist.get(0),usrlist.get(usrlist.size()-1));
                    if( ret < 0 ){
                        log.info("swap Error: ret={},exit.",ret);
                        break;
                    }
                }
                else
                    break;
            }
            List<FiCreditcasesHist> histlist = new ArrayList<>();
            for(int grpIndex=0; grpIndex < usrlist.size(); grpIndex++) {
                usrlist.get(grpIndex).getAssignCaseList().forEach(x -> {
                    x.setStatus(EnumFiCaseStatus.Assign.value);
                    x.setStatusdt(new Date());
                    x.setCcc(EnumFiCaseQueue.Q.value);
                    x.setAssigntype(assignType);
                    x.setAssignid(ruleStepId); //cfgAssignset.getAssignId());
                    x.setAssignusr(usrId);
                    x.setAssigndt(new Date());
                    x.setMdusr(usrId);
                    x.setMddt(new Date());
                    fiCreditcasesService.updateById(x);
                    FiCreditcasesHist fiCreditcasesHist = new FiCreditcasesHist();
                    // 将属性复制到新对象中
                    BeanUtils.copyProperties(x, fiCreditcasesHist);
                    fiCreditcasesHist.setActiontype(2); //派工
                    histlist.add(fiCreditcasesHist);
                });
            }
            fiCreditcasesHistService.saveBatch(histlist);
            return new CmdResVo(totalCnt,"派工完成");
        } catch (Exception e) {
            //XxlJobHelper.log("XXL-JOB-autoAssign, 错误日志:" + e + ">>>>>【异常列】：" + item);
            return new CmdResVo(-1,"异常：" + e.toString());
        }
    }
    private int InitAssignList(Integer distMode, List<AutoAssign> distResVoList, List<FiCreditcases> amtList)
    {
        int casecount=amtList.size();

        if( distMode == 1) {
            Collections.shuffle(distResVoList);
            for( int i = 0; i< distResVoList.size(); i++)
            {
                distResVoList.get(i).setTargetNum1(casecount/distResVoList.size() + ( casecount % distResVoList.size() > i ? 1:0 ));
                distResVoList.get(i).setTargetNum2(0);
                distResVoList.get(i).setTargetNum3(0);
                log.info("InitDistList:CaseCount={},DistAgentCount={},distmode={},keyId={},setTargetNum1={}",
                        amtList.size(),distResVoList.size(),distMode,distResVoList.get(i).getSysUsr().getUsrid(),distResVoList.get(i).getTargetNum1()
                );
            }
        }
        else
        {
            //检查分成三段的比例。
            int totalRatio = 0;
            int ratio1 = 0, ratio2 =0, ratio3=0;
            distResVoList.sort(Comparator.comparing(AutoAssign::getRatio));
            for(int i=0; i<distResVoList.size();i++)
                totalRatio += (int)distResVoList.get(i).getRatio();
            int minRatio = (int)distResVoList.get(0).getRatio();
            if( minRatio * casecount / totalRatio >=4 ) {
                ratio1 = 25;
                ratio2 = 50;
                ratio3 = 25;
            }
            else if( minRatio * casecount / totalRatio >=3 ){
                //30% 40%, 30%
                ratio1 = 30;
                ratio2 = 40;
                ratio3 = 30;
            }
            else if( minRatio * casecount / totalRatio >=2 ){
                ratio1 = 50;
                ratio2 = 50;
                ratio3 = 0;
            }
            else {
                // 100%
                ratio1 = 100;
                ratio2 = 0;
                ratio3 = 0;
            }
            for(int i=0; i< distResVoList.size(); i++)
            {

                distResVoList.get(i).setTargetNum1(0);
                distResVoList.get(i).setTargetNum2(0);
                distResVoList.get(i).setTargetNum3(0);

            }
            Integer distCnt=0, totalDistCnt1=0, totalDistCnt2=0, totalDistCnt3 = 0;
            Integer targetCnt1 = casecount * ratio1 / 100;
            Integer targetCnt2 = casecount * ratio2 / 100;
            Integer targetCnt3 =  casecount - targetCnt1 - targetCnt2;
            if( targetCnt3 == 1)
            {
                targetCnt2 += 1;
                targetCnt3 = 0;
            }
            log.debug( "第一轮待分配的总数：" + targetCnt1);
            Collections.shuffle(distResVoList);
            for (int i = 0; i < distResVoList.size(); i++) {

                distCnt = targetCnt1 * (int)distResVoList.get(i).getRatio()/totalRatio;
                distResVoList.get(i).setDistDivideNum( 1.0 * targetCnt1 * (int)distResVoList.get(i).getRatio()/totalRatio - distCnt);
                distResVoList.get(i).setTargetNum1(distCnt);
                log.debug( "第一轮组织：{}，比例：{}，计划分配数量：{}", distResVoList.get(i).getSysUsr().getUsrid(),
                        distResVoList.get(i).getRatio(), distCnt);
                totalDistCnt1 += distCnt;
            }
            //处理余数

            distResVoList.sort(Comparator.comparing(AutoAssign::getDistDivideNum).reversed());
            for (int i = 0; i < targetCnt1 - totalDistCnt1; i++) {
                distResVoList.get(i).setTargetNum1(distResVoList.get(i).getTargetNum1() + 1);
                log.debug( "第一轮组织：{}，计划分配数量：{}", distResVoList.get(i).getSysUsr().getUsrid(), distResVoList.get(i).getTargetNum1());
            }

            log.debug( "第二轮待分配的总数：{}，ratio:{} ",targetCnt2, ratio2);
            //第二轮
            Collections.shuffle(distResVoList);
            for (int i = 0; i < distResVoList.size(); i++) {

                distCnt = targetCnt2 * (int)distResVoList.get(i).getRatio()/totalRatio;
                distResVoList.get(i).setDistDivideNum( 1.0 * targetCnt2 * (int)distResVoList.get(i).getRatio()/totalRatio - distCnt);
                distResVoList.get(i).setTargetNum2(distCnt);
                log.debug( "第一轮组织：{}，比例：{}，计划分配数量：{}", distResVoList.get(i).getSysUsr().getUsrid(),distResVoList.get(i).getRatio(), distCnt);
                totalDistCnt2 += distCnt;
            }

            //处理余数
            distResVoList.sort(Comparator.comparing(AutoAssign::getDistDivideNum).reversed());
            for (int i = 0; i < targetCnt2 - totalDistCnt2; i++) {
                distResVoList.get(i).setTargetNum2(distResVoList.get(i).getTargetNum2() + 1);
                log.debug( "第二轮组织：{}，计划分配数量：{}", distResVoList.get(i).getSysUsr().getUsrid(), distResVoList.get(i).getTargetNum2());
            }

            //第三轮 25%


            log.debug( "第三轮待分配的总数：" + targetCnt3);
            Collections.shuffle(distResVoList);
            for (int i = 0; i < distResVoList.size(); i++) {
                distCnt = targetCnt3 * (int)distResVoList.get(i).getRatio()/totalRatio;
                distResVoList.get(i).setDistDivideNum( 1.0 * targetCnt3 * (int)distResVoList.get(i).getRatio()/totalRatio - distCnt);
                distResVoList.get(i).setTargetNum3(distCnt);
                log.debug( "第三轮组织：{}，比例：{}，计划分配数量：{}", distResVoList.get(i).getSysUsr().getUsrid(),distResVoList.get(i).getRatio(), distCnt);
                totalDistCnt3 += distCnt;
            }

            //处理余数
            distResVoList.sort(Comparator.comparing(AutoAssign::getDistDivideNum).reversed());
            for (int i = 0; i < targetCnt3 - totalDistCnt3; i++) {
                distResVoList.get(i).setTargetNum3(distResVoList.get(i).getTargetNum3() + 1);
                log.debug( "第三轮组织：{}，计划分配数量：{}", distResVoList.get(i).getSysUsr().getUsrid(), distResVoList.get(i).getTargetNum3());
            }

        }
        for (int i = 0; i < distResVoList.size(); i++) {
            distResVoList.get(i).setTargetDistNum(new Integer[]{distResVoList.get(i).getTargetNum1(),distResVoList.get(i).getTargetNum2(),distResVoList.get(i).getTargetNum3()});
        }

        return distResVoList.size();
    }
    private List<FiCreditcases> getDistObject(int startPos, int needCount, List<FiCreditcases> amList)
    {
        List<FiCreditcases> distCreditcaseVos = new ArrayList<>();

            for(int i=0; i<needCount; i++) {
                distCreditcaseVos.add(amList.get(startPos + i));
            }

        return distCreditcaseVos;
    }
    private Integer swapCase( AutoAssign highGrp, AutoAssign lowGrp)
    {
        Integer highIndex = 0;
        Integer lowIndex = -1;
        FiCreditcases x1 = null;
        FiCreditcases x2 = null;
        if( lowGrp.getAssignCaseList().size() == 0)
            return -1;
        for( int k=0; k< highGrp.getAssignCaseList().size(); k++) {
            x1 = highGrp.getAssignCaseList().get(k);
            highIndex = k;
            lowIndex = -1;
            for (int i = 0; i < lowGrp.getAssignCaseList().size(); i++) {

                x2 = lowGrp.getAssignCaseList().get(lowGrp.getAssignCaseList().size() - i - 1);
                log.info("Swap high distusrid:{}, caseid:{}, amount{}, overratio:{}, " +
                                "to low distgrpid:{}, csaeid:{}, amount{},overratio:{}",
                        highGrp.getSysUsr().getUsrid(), x1.getCreditcaseid(), x1.getCpTotalamt(), highGrp.getOverRatio(),
                        lowGrp.getSysUsr().getUsrid(), x2.getCreditcaseid(), x2.getCpTotalamt(), lowGrp.getOverRatio());

                if(x1.getCpTotalamt().compareTo(x2.getCpTotalamt()) <=0) {
                    log.info("HighGrp Case Amount:{} <= {} LowGrp case Amount, swap fail.",
                            x1.getCpTotalamt(),x2.getCpTotalamt());
                    lowIndex = -2;
                    break;
                }
                else if (1.0 * (lowGrp.getAmount()
                        .add(x1.getCpTotalamt())
                        .subtract(x2.getCpTotalamt()))
                        .doubleValue() / lowGrp.getTagetAmt() > 1.05) {
                    log.info("if swap Lowgrp ratio={} > 1.05, break.", 1.0 * (lowGrp.getAmount()
                            .add(x1.getOverdueTotalamt())
                            .subtract(x2.getOverdueTotalamt()))
                            .doubleValue() / lowGrp.getTagetAmt());
                    lowIndex = -1;
                    break;
                }
                else if (1.0 * (highGrp.getAmount()
                        .add(x2.getCpTotalamt())
                        .subtract(x1.getCpTotalamt()))
                        .doubleValue() / highGrp.getTagetAmt() < 0.95) {
                    log.info("if swap highGrp ratio={}<0.95 ,continue", 1.0 * (highGrp.getAmount()
                            .add(x2.getCpTotalamt())
                            .subtract(x1.getCpTotalamt()))
                            .doubleValue() / highGrp.getTagetAmt());
                    continue;
                }
                else {
                    lowIndex = i;
                    break;
                }
            }
            if (lowIndex == -1)
                continue;
            else if(lowIndex == -2)
                return -1;
            else
                break;
        }
        if( lowIndex == -1) {
            log.info("No find can swap case. swap failed, highGrp:{}, lowGrp:{}",
                    highGrp.getSysUsr().getUsrid(),lowGrp.getSysUsr().getUsrid());
            return -1;
        }
        highGrp.getAssignCaseList().remove(x1);
        x2.setSendtousr(highGrp.getSysUsr().getUsrid());
        highGrp.getAssignCaseList().add(x2);
        highGrp.setAmount(highGrp.getAmount().subtract(x1.getCpTotalamt()));
        highGrp.setAmount(highGrp.getAmount().add(x2.getCpTotalamt()));
        highGrp.setOverRatio(1.0 * highGrp.getAmount().doubleValue()/highGrp.getTagetAmt());
        lowGrp.getAssignCaseList().remove(x2);
        x1.setSendtousr(lowGrp.getSysUsr().getUsrid());
        lowGrp.getAssignCaseList().add(x1);
        lowGrp.setAmount(lowGrp.getAmount().subtract(x2.getCpTotalamt()));
        lowGrp.setAmount(lowGrp.getAmount().add(x1.getCpTotalamt()));
        lowGrp.setOverRatio(1.0 * lowGrp.getAmount().doubleValue()/lowGrp.getTagetAmt());
        log.info("Swap OK, high usrid:{}, overratio:{}, low usrid:{},overratio:{}",
                highGrp.getSysUsr().getUsrid(),highGrp.getOverRatio(),lowGrp.getSysUsr().getUsrid(),lowGrp.getOverRatio());
        return 0;
    }
    private void disUsersToCases(List<FiCreditcases> caseList, List<CfgAssignratio> userList) {
        int totalCases = caseList.size(),
                totalUsers = userList.size(),
                casesPerUser = totalCases / totalUsers,   // 计算每个用户应该分配的案例数量
                extraCases = totalCases % totalUsers,     // 计算余下的案例数量
                caseIndex = 0;

        for (CfgAssignratio item : userList) {
            int assignedCases = casesPerUser + (extraCases > 0 ? 1 : 0); // 每个用户应该分配的案例数量
            for (int i = 0; i < assignedCases; i++) {
                caseList.get(caseIndex).setSendtousr(item.getUsrid());
                caseIndex++;
            }
            extraCases--; // 余下的案例数量减少
        }
    }
}




